#ifndef TASK_EVENTLOOP_H
#define TASK_EVENTLOOP_H

#include <vector>
#include <memory>
#include <functional>

#include "../../base/noncopyable.h"
#include "../../base/thread/Thread.h"
#include "../../base/Timestamp.h"
#include "../../base/thread/Mutex.h"
#include "TimerId.h"

class Poller;

class Channel;

class TimerQueue;

class EventLoop : muduo::noncopyable {
public:
    typedef std::function<void()> TimerCallback;
    typedef std::function<void()> Functor;

    EventLoop();

    ~EventLoop();

    /**
     * 启动事件循环
     */
    void loop();

    /**
     * 关闭现在的事件循环
     */
    void quit();

    ///
    /// Time when poll returns, usually means data arrival.
    ///
    Timestamp pollReturnTime() const { return pollReturnTime_; }

    /**
     * 将函数传入到EventLoop对应的线程的事件循环中执行
     * 如果当前线程是IO线程就直接运行, 如果不是的话就添加到待运行队列中去执行
     * @param cb 待运行的函数
     */
    void runInLoop(const Functor &cb);

    /**
     * 将待运行的事件传入到当前线程的待执行队列中等待执行
     * @param cb 待运行的事件
     */
    void queueInLoop(const Functor &cb);

    /**
     * 从指定时间调用
     * @param time 指定调用时间
     * @param cb 回调事件
     * @return 返回标识id
     */
    TimerId runAt(Timestamp time, TimerCallback cb);

    /**
     * 延迟delay秒后进行调用, 保证是线程安全的
     * @param delay 延迟时间, 单位 : s
     * @param cb 调用事件
     * @return 返回对应时间时间标识id
     */
    TimerId runAfter(double delay, TimerCallback cb);

    /**
     * 每隔interval秒运行一次回调
     * 可以安全地从其他线程调用。
     * @param interval 间隔时间
     * @param cb 回调函数
     * @return 执行的时间时间的id
     */
    TimerId runEvery(double interval, TimerCallback cb);

    /**
     * 移除指定的事件id对应的时间事件
     * @param timerId 指定的事件id
     */
    void cancel(TimerId timerId);

    /**
     * 用于唤醒poller, 用以执行后续任务用
     */
    void wakeup();

    /**
     * 更新文件描述符对应的文件事件
     * @param channel 待更新的文件描述符事件
     */
    void updateChannel(Channel *channel);

    /**
    * 移除文件描述符对应的文件事件
    * @param channel 移除的文件描述符事件
    */
    void removeChannel(Channel *channel);

    bool hasChannel(Channel *channel);

    bool isInLoopThread() const { return threadId_ == CurrentThread::getTid(); }

    void assertInLoopThread() { if (!isInLoopThread()) abortNotInLoopThread(); }

    static EventLoop *getEventLoopOfCurrentThread();

private:
    typedef std::vector<Channel *> ChannelList;

    /**
     * 此时没有在loop对应的线程中调用, 所以记录到日志中
     */
    void abortNotInLoopThread();

    /**
     *  用于唤醒事件循环用, 该函数会被封装进poll的事件监听循环中
     */
    void handleRead();

    /**
     * 执行延迟的函数
     */
    void doPendingFunctors();

    bool looping_;
    // 标识现在是否有事件循环在执行
    bool quit_;
    bool eventHandling_;
    bool callingPendingFunctors_;
    // 用于判断现在使用在IO线程中
    const pid_t threadId_;
    // 记录当前事件池所在线程
    Timestamp pollReturnTime_;
    std::unique_ptr<Poller> poller_;
    std::unique_ptr<TimerQueue> timerQueue_;
    int wakeupFd_;
    // 用于唤醒阻塞在poll的线程
    std::unique_ptr<Channel> wakeupChannel_;
    // 用于处理wakeupFd上的readable事件, 并将事件分发到handle-Read()函数中

    ChannelList activeChannels_;
    // 当前活动的channels集合
    Channel *currentActiveChannel_;

    MutexLock mutex_;
    // 用于保护下面的pendingFunctors的,
    std::vector<Functor> pendingFunctors_;
};

#endif //TASK_EVENTLOOP_H
